import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

/// 支持双指缩放和拖动的视频播放器组件
/// 缩放范围：1-6倍
/// 放大后可以拖动查看不同区域
class ZoomableVideoPlayer extends StatefulWidget {
  final VideoPlayerController controller;
  final BoxFit fit;
  final ValueChanged<double>? onScaleChanged; // 缩放比例变化回调

  const ZoomableVideoPlayer({
    super.key,
    required this.controller,
    this.fit = BoxFit.contain,
    this.onScaleChanged,
  });

  @override
  State<ZoomableVideoPlayer> createState() => _ZoomableVideoPlayerState();
}

class _ZoomableVideoPlayerState extends State<ZoomableVideoPlayer> {
  // 当前缩放比例（1.0 - 6.0）
  double _scale = 1.0;

  // 上次缩放比例（用于计算增量）
  double _previousScale = 1.0;

  // 当前偏移量
  Offset _offset = Offset.zero;

  // 上次偏移量（用于拖动）
  Offset _previousOffset = Offset.zero;

  // 手势开始时的焦点位置
  Offset? _focalPointStart;

  // 最小缩放比例
  static const double _minScale = 1.0;

  // 最大缩放比例
  static const double _maxScale = 6.0;

  @override
  void didUpdateWidget(ZoomableVideoPlayer oldWidget) {
    super.didUpdateWidget(oldWidget);
    // 当 controller 变化时（重新加载视频），重置缩放和偏移
    if (widget.controller != oldWidget.controller) {
      _resetZoom();
    }
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        return GestureDetector(
          // 手势开始（支持单指和双指）
          onScaleStart: (details) {
            _previousScale = _scale;
            _previousOffset = _offset;
            _focalPointStart = details.focalPoint;
          },

          // 手势更新（处理缩放和拖动）
          onScaleUpdate: (details) {
            setState(() {
              // 判断是指针数量：1个指针可能是拖动，2个或更多指针是缩放
              final pointerCount = details.pointerCount;

              if (pointerCount > 1) {
                // 双指或多指：处理缩放
                double newScale = _previousScale * details.scale;
                newScale = newScale.clamp(_minScale, _maxScale);
                _scale = newScale;

                // 通知缩放比例变化
                widget.onScaleChanged?.call(_scale);

                // 缩放时也更新偏移量（跟随焦点）
                if (_scale > 1.0 && _focalPointStart != null) {
                  final focalPointDelta =
                      details.focalPoint - _focalPointStart!;
                  final newOffset = Offset(
                    _previousOffset.dx + focalPointDelta.dx,
                    _previousOffset.dy + focalPointDelta.dy,
                  );
                  _offset = _limitOffset(newOffset, _scale, constraints);
                } else {
                  // 当缩放比例回到1.0或更小时，重置偏移量
                  _offset = Offset.zero;
                }
              } else if (pointerCount == 1 && _scale > 1.0) {
                // 单指且已放大：处理拖动
                // 使用 focalPoint 相对于开始位置的差值来计算偏移量，更可靠
                if (_focalPointStart != null) {
                  final focalPointDelta =
                      details.focalPoint - _focalPointStart!;
                  final newOffset = Offset(
                    _previousOffset.dx + focalPointDelta.dx,
                    _previousOffset.dy + focalPointDelta.dy,
                  );
                  _offset = _limitOffset(newOffset, _scale, constraints);
                }
              }
            });
          },

          // 手势结束
          onScaleEnd: (details) {
            // 如果缩放比例小于1.0，自动回到1.0
            if (_scale < _minScale) {
              _resetZoom();
              return;
            }

            setState(() {
              // 当缩放比例回到1.0时，确保偏移量被重置
              if (_scale <= 1.0) {
                _offset = Offset.zero;
                _previousOffset = Offset.zero;
              } else {
                // 缩放比例大于1.0时，确保偏移量被限制在合理范围内
                _offset = _limitOffset(_offset, _scale, constraints);
                _previousOffset = _offset;
              }
            });

            // 重置状态
            _focalPointStart = null;
          },

          // 双击重置缩放
          onDoubleTap: () {
            _resetZoom();
          },

          child: Stack(
            fit: StackFit.expand,
            children: [
              // 黑色背景，用于填充视频移出可视区域后的空白
              Container(color: Colors.black),
              // 可拖动的视频
              Transform(
                transform:
                    Matrix4.identity()
                      ..translate(_offset.dx, _offset.dy)
                      ..scale(_scale),
                alignment: Alignment.center,
                child: SizedBox.expand(
                  child: FittedBox(
                    fit: widget.fit,
                    child: SizedBox(
                      width: widget.controller.value.size.width,
                      height: widget.controller.value.size.height,
                      child: VideoPlayer(widget.controller),
                    ),
                  ),
                ),
              ),
            ],
          ),
        );
      },
    );
  }

  /// 限制偏移量，确保视频不会被拖动到完全移出可视区域
  /// 只计算视频实际显示区域，避免溢出
  Offset _limitOffset(Offset offset, double scale, BoxConstraints constraints) {
    // 如果缩放比例为1.0，不需要限制
    if (scale <= 1.0) {
      return Offset.zero;
    }

    // 获取容器尺寸
    final containerWidth = constraints.maxWidth;
    final containerHeight = constraints.maxHeight;

    // 获取视频原始尺寸
    final videoWidth = widget.controller.value.size.width;
    final videoHeight = widget.controller.value.size.height;

    if (videoWidth <= 0 || videoHeight <= 0) {
      return offset;
    }

    // 计算视频在 BoxFit.contain 下的实际显示尺寸
    final videoAspectRatio = videoWidth / videoHeight;
    final containerAspectRatio = containerWidth / containerHeight;

    double displayWidth;
    double displayHeight;

    if (videoAspectRatio > containerAspectRatio) {
      // 视频更宽，以宽度为准
      displayWidth = containerWidth;
      displayHeight = containerWidth / videoAspectRatio;
    } else {
      // 视频更高，以高度为准
      displayHeight = containerHeight;
      displayWidth = containerHeight * videoAspectRatio;
    }

    // 计算缩放后的视频尺寸
    final scaledWidth = displayWidth * scale;
    final scaledHeight = displayHeight * scale;

    // 计算可移动的最大范围
    // 偏移量应该限制在：-(缩放后尺寸 - 容器尺寸) / 2 到 (缩放后尺寸 - 容器尺寸) / 2
    final maxOffsetX = (scaledWidth - containerWidth) / 2;
    final maxOffsetY = (scaledHeight - containerHeight) / 2;

    // 限制偏移量在合理范围内
    // 只有当缩放后的视频尺寸大于容器尺寸时，才需要限制偏移量
    // 确保 clamp 的参数顺序正确（最小值 <= 最大值）
    double limitedOffsetX;
    if (maxOffsetX > 0) {
      // X 方向超出容器，需要限制偏移量
      limitedOffsetX = offset.dx.clamp(-maxOffsetX, maxOffsetX);
    } else {
      // X 方向未超出容器，不允许偏移
      limitedOffsetX = 0.0;
    }

    double limitedOffsetY;
    if (maxOffsetY > 0) {
      // Y 方向超出容器，需要限制偏移量
      limitedOffsetY = offset.dy.clamp(-maxOffsetY, maxOffsetY);
    } else {
      // Y 方向未超出容器，不允许偏移
      limitedOffsetY = 0.0;
    }

    return Offset(limitedOffsetX, limitedOffsetY);
  }

  /// 重置缩放和偏移
  void _resetZoom() {
    setState(() {
      _scale = _minScale;
      _offset = Offset.zero;
      _previousScale = _minScale;
      _previousOffset = Offset.zero;
    });
    // 通知缩放比例变化
    widget.onScaleChanged?.call(_scale);
  }
}
